/*
* License: source-license.txt
* If this code is used independently, copy the license here.
*/
package wombat.scheme.libraries;
import java.awt.FileDialog;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.*;
import javax.imageio.*;
import wombat.scheme.libraries.gui.ImageFrame;
import wombat.scheme.libraries.types.ImageData;
/**
* Helper class to load, save, and display images using Java.
*/
public class ImageAPI {
private ImageAPI() {}
/**
* Show a dialog to allow the user to choose an image, then read it into a byte stream.
* @param dir The directory to read from.
* @return A stream of encoded data. The first two values are rows then columns, then the sequence is [r,g,b,a] across rows then down.
* @throws IOException If we cannot read the file.
*/
public static ImageData readImage() throws IOException {
FileDialog fc = new FileDialog((java.awt.Frame) null, "read-image", FileDialog.LOAD);
fc.setVisible(true);
if (fc.getFile() == null)
throw new IllegalArgumentException("Error in read-image: no image chosen.");
File file = new File(fc.getDirectory(), fc.getFile());
return readImage(null, file.getCanonicalPath());
}
/**
* Read an image into a bytestream.
* @param dir The directory to read from.
* @param filename The file to read.
* @return A stream of encoded data. The first two values are rows then columns, then the sequence is [r,g,b,a] across rows then down.
* @throws IOException If we cannot read the image.
*/
public static ImageData readImage(String dir, String filename) throws IOException {
if (!new File(filename).isAbsolute())
filename = new File(dir, filename).getCanonicalPath();
if (!new File(filename).exists())
throw new IllegalArgumentException("Error in read-image: '" + filename + "' does not exist");
BufferedImage bi_orig = ImageIO.read(new File(filename));
if (bi_orig == null) {
String filetypes = "";
for (String s : ImageIO.getReaderFileSuffixes())
filetypes += s + " ";
filetypes = filetypes.trim();
throw new IllegalArgumentException("Error in read-image: Unable to read '" + filename + "'. Valid file types are: " + filetypes);
}
// This is a fix to deal with getRGB screwing up on previously grayscale images
BufferedImage bi = new BufferedImage(bi_orig.getWidth(), bi_orig.getHeight(), BufferedImage.TYPE_INT_ARGB);
bi.getGraphics().drawImage(bi_orig, 0, 0, null);
int[] data = new int[bi.getWidth() * bi.getHeight()];
bi.getRGB(0, 0, bi.getWidth(), bi.getHeight(), data, 0, bi.getWidth());
return new ImageData(bi.getWidth(), bi.getHeight(), data);
}
/**
* Write the image. Display a dialog for the filename.
* @param dir The directory to read from.
* @param data The image to write.
* @throws IOException If we cannot write the image.
*/
public static void writeImage(Image img) throws IOException {
FileDialog fc = new FileDialog((java.awt.Frame) null, "write-image", FileDialog.SAVE);
fc.setVisible(true);
if (fc.getFile() == null)
throw new IllegalArgumentException("Error in read-image: no image chosen");
File file = new File(fc.getDirectory(), fc.getFile());
String[] parts = file.getName().split("\\.");
ImageIO.write((RenderedImage) img, parts[parts.length - 1], file);
}
/**
* Write the given [r,g,b,a] buffer to an image. Display a dialog for the filename.
* @param dir The directory to read from.
* @param data The image to write. The first two values are the width and height.
* @throws IOException If we cannot write the image.
*/
public static void writeImage(ImageData img) throws IOException {
FileDialog fc = new FileDialog((java.awt.Frame) null, "write-image", FileDialog.SAVE);
fc.setVisible(true);
if (fc.getFile() == null)
throw new IllegalArgumentException("Error in read-image: no image chosen");
File file = new File(fc.getDirectory(), fc.getFile());
writeImage(null, img, file.getCanonicalPath());
}
/**
* Write the given [r,g,b,a] buffer to an image.
* @param dir The directory to read from.
* @param data The image to write. The first two values are the width and height.
* @param filename The file to write to.
* @throws IOException If we cannot write the image.
*/
public static void writeImage(String dir, ImageData img, String filename) throws IOException {
RenderedImage ri = new BufferedImage(img.Width, img.Height, BufferedImage.TYPE_INT_RGB);
((BufferedImage) ri).setRGB(0, 0, img.Width, img.Height, img.Data, 0, img.Width);
if (!new File(filename).isAbsolute())
filename = new File(dir, filename).getCanonicalPath();
File file = new File(filename);
String[] parts = file.getName().split("\\.");
ImageIO.write(ri, parts[parts.length - 1], file);
}
/**
* Display the given [r,g,b,a] buffer as an image.
* @param data The image to write. The first two values are the width and height.
* @throws IOException If we cannot write the image.
*/
public static void displayImage(ImageData img) {
final RenderedImage ri = new BufferedImage(img.Width, img.Height, BufferedImage.TYPE_INT_RGB);
((BufferedImage) ri).setRGB(0, 0, img.Width, img.Height, img.Data, 0, img.Width);
// Create the basic frame.
new ImageFrame((Image) ri).setVisible(true);
}
}